package cn.ywyu.classfinal;

import cn.ywyu.classfinal.constant.Const;
import cn.ywyu.classfinal.jar.JarEncryptor;
import cn.ywyu.classfinal.util.*;
import lombok.Data;

import java.io.File;
import java.util.List;
import java.util.Optional;
import java.util.Scanner;


/**
 * 加密普通jar，springboot jar，spring web war
 * 启动 java -jar this.jar
 * 启动2 java -jar this.jar -file springboot.jar -libjars a.jar,b.jar -packages cn.ywyu,yiyon.com -exclude org.spring -pwd 995800 -Y
 */
public class Main {
    /**
     * 入口方法
     *
     * @param args 参数
     */
    public static void main(String[] args) {
        Const.printInfo();
        // 命令行参数
        CmdLineArgs cmdArgs = new CmdLineArgs();
        // 获取参数解析
        CmdLineParser cmdParser = CmdLineParser.createEncryptParser(args);

        try (Scanner scanner = new Scanner(System.in)) {
            // 没有参数手动输入
            if (args.length == 0) {
                inputCmdLineParams(scanner, cmdArgs);
            } else {
                // 生成机器码
                if (cmdParser.usedOption("C")) {
                    makeCode();
                    return;
                }
                cmdArgs.setFile(cmdParser.getOptionValue("file"));
                cmdArgs.setLibjars(cmdParser.getOptionValue("libjars"));
                cmdArgs.setPackages(cmdParser.getOptionValue("packages"));
                cmdArgs.setExclude(cmdParser.getOptionValue("exclude"));
                cmdArgs.setClasspath(cmdParser.getOptionValue("classpath"));
                cmdArgs.setPwd(cmdParser.getOptionValue("pwd"));
                cmdArgs.setCode(cmdParser.getOptionValue("code"));
                cmdArgs.setCfgfiles(cmdParser.getOptionValue("cfgfiles"));
            }

            // debug
            setDebugParams(cmdArgs, cmdArgs.getFile());

            // 打印信息
            cmdArgs.printInfo();

            if (!cmdParser.usedOption("Y") && !confirm(scanner)) {
                Log.println("已取消！");
                return;
            }

            // 加密
            encrypt(cmdArgs);
        }
    }

    private static boolean confirm(Scanner scanner) {
        Log.println("确定执行吗？(Y/N)");
        String yes = scanner.nextLine().trim();
        while (!"N".equalsIgnoreCase(yes) && !"Y".equalsIgnoreCase(yes)) {
            Log.println("Yes or No ？[Y/N]");
            yes = scanner.nextLine().trim();
        }
        return "Y".equalsIgnoreCase(yes);
    }

    private static void inputCmdLineParams(Scanner scanner, CmdLineArgs cmdArgs) {
        while (StrUtils.isEmpty(cmdArgs.getFile())) {
            Log.print("请输入需要加密的jar/war路径:");
            cmdArgs.setFile(scanner.nextLine().trim());
        }

        Log.print("请输入jar/war包lib下要加密jar文件名(可为空,多个用\",\"分割):");
        cmdArgs.setLibjars(scanner.nextLine().trim());

        Log.print("请输入需要加密的包名(可为空,多个用\",\"分割):");
        cmdArgs.setPackages(scanner.nextLine().trim());

        Log.print("请输入需要排除的类名(可为空,多个用\",\"分割):");
        cmdArgs.setExclude(scanner.nextLine().trim());

        Log.print("请输入依赖jar包目录(可为空,多个用\",\"分割):");
        cmdArgs.setClasspath(scanner.nextLine().trim());

        Log.print("请输入要加密的配置文件名(可为空,多个用\",\"分割):");
        cmdArgs.setCfgfiles(scanner.nextLine().trim());

        Log.print("请输入机器码(可为空):");
        cmdArgs.setCode(scanner.nextLine().trim());

        while (StrUtils.isEmpty(cmdArgs.getPwd())) {
            Log.print("请输入加密密码:");
            cmdArgs.setPwd(scanner.nextLine().trim());
        }
    }


    private static void encrypt(CmdLineArgs cmdArgs) {
        Log.println("处理中...");
        List<String> includeJarList = StrUtils.toList(cmdArgs.getLibjars());
        List<String> packageList = StrUtils.toList(cmdArgs.getPackages());
        List<String> excludeClassList = StrUtils.toList(cmdArgs.getExclude());
        List<String> classPathList = StrUtils.toList(cmdArgs.getClasspath());
        List<String> cfgFileList = StrUtils.toList(cmdArgs.getCfgfiles());

        JarEncryptor encryptor = new JarEncryptor(cmdArgs.getFile(), cmdArgs.getPwd().trim().toCharArray());
        encryptor.setCode(Optional.ofNullable(cmdArgs.getCode()).map(code -> code.trim().toCharArray()).orElse(null));
        encryptor.setPackages(packageList);
        encryptor.setIncludeJars(includeJarList);
        encryptor.setExcludeClass(excludeClassList);
        encryptor.setClassPath(classPathList);
        encryptor.setCfgFiles(cfgFileList);
        try {
            String result = encryptor.doEncryptJar();
            Log.println("加密完成，请牢记密码！");
            Log.println("==>" + result);
        } catch (Exception e) {
            Log.println("ERROR: " + e.getMessage());
        }
    }

    /**
     * 生成机器码
     */
    private static void makeCode() {
        String path = JarUtils.getRootPath(null);
        path = path.substring(0, path.lastIndexOf(File.separator) + 1);

        String code = new String(SysUtils.makeMachineCode());
        File file = new File(path, "classfinal-code.txt");
        IoUtils.writeTxtFile(file, code);
        Log.println("Server code is: " + code);
        Log.println("==>" + file.getAbsolutePath());
        Log.println();
    }

    private static void setDebugParams(CmdLineArgs cmdArgs, String debug) {
        switch (debug) {
            case "1":
                Log.enableDebug(true);
                cmdArgs.setFile("D:/AAAAA/Desktop/nyg-project-0.0.1-SNAPSHOT.jar");
                cmdArgs.setPackages("com.nyg,cn.hutool");
                cmdArgs.setExclude("org.spring");
                cmdArgs.setLibjars("hutool-all-5.8.25.jar");
                cmdArgs.setCfgfiles("*.yml");
                cmdArgs.setPwd("abc");
                break;
            case "2":
                // do something
                break;
            default:
                break;
        }
    }

    @Data
    private static class CmdLineArgs {
        private String file;
        private String libjars;
        private String packages;
        private String exclude;
        private String classpath;
        private String pwd;
        private String code;
        private String cfgfiles;

        public void printInfo() {
            Log.println();
            Log.println("加密信息如下:");
            Log.println("-------------------------");
            Log.println("1. jar/war路径:      " + file);
            Log.println("2. lib下的jar:       " + libjars);
            Log.println("3. 包名前缀:          " + packages);
            Log.println("4. 排除的类名:        " + exclude);
            Log.println("5. 加密配置文件:      " + cfgfiles);
            Log.println("6. ClassPath:       " + classpath);
            Log.println("7. 密码:             " + pwd);
            Log.println("8. 机器码:           " + code);
            Log.println("-------------------------");
            Log.println();
        }
    }
}
